package com.ale.oxetool.model;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * Created by wgs on 2016/4/3.
 * TODO: Implement a reset timeout timer
 */
public class SwitchTask {
    public static final int NOT_START = 0;
    public static final int IN_PROGRESS = 1;
    public static final int DONE = 2;
    public static final int FAIL = 3;
    public static final int TIMEOUT = 4;

    private int exceptionStatusCounter=0;

    public int getExceptionStatusCounter() {
        return exceptionStatusCounter;
    }

    public void setExceptionStatusCounter(int exceptionStatusCounter) {
        this.exceptionStatusCounter = exceptionStatusCounter;
    }

    private Phone phone;
    private volatile int status = NOT_START;
    private volatile int previousStatus = NOT_START;
    private String description;

    private String targetPlatform;

    private BatchSwitchTask batch;

    // reset timeout seconds
    private int resetTimeout;
    private AtomicInteger countdown;

    private Timer resetTimer;
    private TimerTask resetTimeoutTask = new ResetTimeOutTimeTask();

    private static Logger log = LoggerFactory.getLogger(SwitchTask.class);

    public SwitchTask(Phone phone, int status, String targetPlatform, String description, int resetTimeout) {
        this.phone = phone;
        this.status = status;
        this.targetPlatform = targetPlatform;
        this.description = description;
        this.resetTimeout = resetTimeout;

        this.countdown = new AtomicInteger(resetTimeout);

        resetTimer = new Timer("SwitchTask_" + this.phone.getIpAddr());
    }

    public SwitchTask(Phone phone, int status, String targetPlatform, String description) {
        this(phone, status, targetPlatform, description, 0);
    }

    public int getCountdown() {
        return countdown.get();
    }

    public BatchSwitchTask getBatch() {
        return batch;
    }

    void setBatch(BatchSwitchTask batch) {
        this.batch = batch;
    }

    public String getTargetPlatform() {
        return targetPlatform;
    }

    public void setTargetPlatform(String targetPlatform) {
        this.targetPlatform = targetPlatform;
    }

    public Phone getPhone() {
        return phone;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }

    public int getStatus() {
        return this.status;
    }

    public void setResetTimeout(int resetTimeout) {
        this.resetTimeout = resetTimeout;
    }

    public int getResetTimeout() {
        return resetTimeout;
    }

    private class ResetTimeOutTimeTask extends TimerTask {
        @Override
        public void run() {
            log.debug("SwitchTask for phone {} counter: {}", phone, countdown.get());
            if (countdown.decrementAndGet() <= 0) {
                SwitchTask.this.status = TIMEOUT;

                this.cancel();
                resetTimer.cancel();
                log.debug("SwitchTask for phone {} timeout, timer task cancelled.", phone);
            }
            SwitchTask.this.batch.updateCurrentStatus();
        }
    }

    public synchronized void setStatus(int status) {
        // if status not changed and counter nothing need to be done.
        if (status == this.status) {
            return;
        }

        if (resetTimeout > 0 && NOT_START == this.status && IN_PROGRESS == status) {
            long duration = MILLISECONDS.convert(1, SECONDS);
            resetTimer.scheduleAtFixedRate(resetTimeoutTask, duration, duration);
        }

        // state switch back into not start means failed
        if (this.previousStatus != NOT_START && status == NOT_START) {
            this.previousStatus = NOT_START;
            this.status = FAIL;
            resetTimer.cancel();
        }else{
            this.previousStatus = this.status;
            this.status = status;
        }
        if (DONE == status) {
            log.debug("Switch task {} has done, cancel reset timer.", this);
            resetTimer.cancel();
        }
        //update status as a whole
//        this.batch.updateCurrentStatus();
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "SwitchTask{" + "phone=" + phone +
                ", targetPlatform='" + targetPlatform + '\'' +
                ", status=" + status +
                '}';
    }
}
